<?php

function makeClassName($name){
	$names = explode("_", $name);
	array_walk($names, "makeFirstUpper");
	return implode("", $names);
}

function makeFirstUpper(&$value, $key){
	$value = ucfirst($value);
}

function trimAll(&$value, $key, $param){
	$value = trim($value, $param);
}

class Mvc_Updater{
	/**
	 * @var Database
	 */
	private $db;

	public function __construct(Database $db){
		$this->db = $db;
	}

	public function updateAll(){
		$query = "SHOW TABLES;";
		$res = $this->db->prepare($query)->fetchObjectAll();

		if($res){
			foreach( $res as $table){
				$this->update(current(get_object_vars($table)));
			}
		}
	}

	public function update( $name ){

		$tname = $name;

		$name = makeClassName($name);

		$backupDir = APP . 'models' . DIRECTORY_SEPARATOR . 'backup/';
		$php = APP . 'models' . DIRECTORY_SEPARATOR . $name . '.php';
		$lock = APP . 'models' . DIRECTORY_SEPARATOR . $name . '.lock';

		if(!file_exists($lock)){

			$query = "DESCRIBE {$tname};";
			$res = $this->db->prepare($query)->fetchObjectAll();

			$inheritance = $this->getInheritance($tname);
			$count = count($inheritance);
			$class = "";
			$imploded = implode(", ", $inheritance);

//			if( $count == 1){
//				$class = "<?php\nclass {$name} extends {$imploded} implements DBObject{\n";
//			}elseif( $count > 1 ){
			if( $count > 0){
				$class = "<?php\n/** extends {$imploded} */\nclass {$name} implements DBObject{\n";
			}else{
				$class = "<?php\nclass {$name} implements DBObject{\n";
			}

			foreach($res AS $columns){
				$default = ("NO" == $columns->Null && $columns->Default) ? " = '{$columns->Default}'" : "";

				if(false !== strpos($columns->Type, "enum"))
					$this->createEnum($columns->Field, $columns->Type);
				if(false !== strpos($columns->Type, "set"))
					$this->createSet($columns->Field, $columns->Type);

				$class .=
"
	/**
	 * Default = '{$columns->Default}'<br />
	 * Null = '{$columns->Null}',<br />
	 * Extra's = '{$columns->Extra}',<br />
	 * @var {$columns->Type}
	 */
	 public \${$columns->Field}{$default};
";
			}

			$class .= "}\n";

			if(file_exists($php)){
				if(!file_exists($backupDir))
					mkdir($backupDir);

				rename($php, $backupDir . $name . '.php');
			}

			file_put_contents($php, $class);
			chmod($php, 0777);

			$class = "<?php\nclass Mapper_{$name} extends DBTable{\n\n\tpublic function __construct(Database \$db = null){\n\t\tparent::__construct(\"{$tname}\", \$db);\n\t}\n}";

			$php = APP . 'models' . DIRECTORY_SEPARATOR . 'Mapper' . DIRECTORY_SEPARATOR . $name . '.php';
			if(file_exists($php))
				return;

			file_put_contents($php, $class);
			chmod($php, 0777);
		}
	}

	public function createSet($name, $set){
		$name = makeClassName($name);

		$class = "<?php\nclass Set_{$name} extends Enum_Flags{\n";

		$set = str_replace("'", '"', trim(substr($set, strlen("set")), "()"));

		$class .= "\tpublic function __construct(){\n\t\tparent::__construct({$set});\n\t}\n}";

		$php = APP . 'models' . DIRECTORY_SEPARATOR . 'Set' . DIRECTORY_SEPARATOR . $name . '.php';

		file_put_contents($php, $class);
		chmod($php, 0777);
	}

	public function createEnum($name, $enum){
		$name = makeClassName($name);

		$class = "<?php\nclass Enum_{$name} extends Enum{\n";

		$enum = str_replace("'", '"', trim(substr($enum, strlen("enum")), "()"));

		$class .= "\tpublic function __construct(){\n\t\tparent::__construct({$enum});\n\t}\n}";

		$php = APP . 'models' . DIRECTORY_SEPARATOR . 'Enum' . DIRECTORY_SEPARATOR . $name . '.php';

		file_put_contents($php, $class);
		chmod($php, 0777);
	}

	public function getInheritance($name){
		$query = "SHOW CREATE TABLE {$name};";

		$create = $this->db->prepare($query)->fetchObjectOnce()->{"Create Table"};

		$lines = explode("\n", $create);
		$constraints = array();

		foreach($lines as $line){
			if( false !== stripos($line, "CONSTRAINT"))
				$constraints[] = trim($line, " ,");
		}

		$match = "=^CONSTRAINT `[^`]+` FOREIGN KEY \(`[^`]+`\) REFERENCES `([^`]+)`=i";
		$list = array();
		foreach($constraints as $constraint){
			if( preg_match($match, $constraint, $matches) ){
				$list[] = makeClassName($matches[1]);
			}
		}
		return $list;
	}
}